package org.nanotek.lucene.index.search.local;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.util.Version;
import org.nanotek.cms.domain.lucene.ScoreDocument;
import org.nanotek.lucene.query.ContextKeys;
import org.nanotek.lucene.query.QueryContext;
import org.nanotek.lucene.query.QueryDispatcher;
import org.nanotek.lucene.query.QueryException;
import org.nanotek.lucene.query.QueryObject;
import org.nanotek.lucene.query.QueryResult;

/**
 *
 * The Base Dispatcher to manipulate simple IndexSearcher Objects. Designed for
 * small index and running on servers or local machines.
 *
 * @author JoseCanova
 *
 */
public abstract class LocalBaseQueryDispatcher implements  LocalQueryDispatcher {

	// TODO: Configure Index Reader on Spring
	// private IndexReader indexReader;
	private Version luceneVersion;
	private QueryParser queryParser;
	// TODO: Configure IndexSearcher on Spring
	private IndexSearcher indexSearcher;

	@Override
	public QueryResult executeQuery(QueryContext queryContext) {
		QueryResult results = null;
		int maxResult;
		TopDocs topDocs = null;
		List<ScoreDocument> documents = null;
		try {
			if (indexSearcher != null) {
				String escapedQuery = QueryParser.escape((String) queryContext
						.getSearchPhrase());
				if (queryParser == null)
					queryParser = new QueryParser(
							Version.LUCENE_40,
							queryContext.get(ContextKeys.TARGET_FIELD).toString(),
							new StandardAnalyzer(Version.LUCENE_40));
				Query query = queryParser.parse(escapedQuery);
				if (queryContext.get(ContextKeys.LAST_SCORED_DOC) != null) {
					ScoreDoc scoreDoc = (ScoreDoc) queryContext
							.get(ContextKeys.LAST_SCORED_DOC);
					maxResult = queryContext.getMaxHits();
					topDocs = indexSearcher.searchAfter(scoreDoc, query,
							maxResult);
				} else {
					topDocs = indexSearcher.search(query,
							queryContext.getMaxHits());
				}
				if (topDocs != null && topDocs.totalHits > 0) {
					documents = getDocuments(indexSearcher, topDocs);
				}
				results = new QueryResult();
				results.setTopDocs(topDocs);
				results.setDocuments(documents);
			} else {
				throw new QueryException(" Reader is Null ");
			}
		} catch (Exception e) {
			throw new QueryException(e);
		}
		return results;
	}

	private List<ScoreDocument> getDocuments(IndexSearcher indexSearcher,
			TopDocs topDocs) throws IOException {
		List<ScoreDocument> documents = new ArrayList<ScoreDocument>();
		ScoreDoc[] hits = topDocs.scoreDocs;
		int numTotalHits = topDocs.totalHits;
		System.out.println(numTotalHits + " total matching documents");
		for (int i = 0; i < hits.length; i++) {
			Document doc = indexSearcher.doc(hits[i].doc);
			if (doc != null) {
				ScoreDocument scoreDoc = new ScoreDocument();
				scoreDoc.setScoreDoc(hits[i]);
				scoreDoc.setDocument(doc);
				documents.add(scoreDoc);
			}
		}
		return documents;
	}

	public Version getLuceneVersion() {
		return luceneVersion;
	}

	public void setLuceneVersion(Version luceneVersion) {
		this.luceneVersion = luceneVersion;
	}

	public QueryParser getQueryParser() {
		return queryParser;
	}

	public void setQueryParser(QueryParser queryParser) {
		this.queryParser = queryParser;
	}

	public IndexSearcher getIndexSearcher() {
		return indexSearcher;
	}

	public void setIndexSearcher(IndexSearcher indexSearcher) {
		this.indexSearcher = indexSearcher;
	}

}
